package visualization.ganeat;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Rectangle2D;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import optimizers.ganeat.Individual;
import optimizers.ganeat.Species;
import optimizers.ganeat.sin.IndividualSin;
import visualization.GraphDisplayer;

public class PlotSpeciesData extends JPanel implements MouseListener,
		MouseMotionListener {
	private ArrayList<ArrayList<Species>> speciesData;
	private Map<Species, Rectangle> speciesRectangles;
	private Map<Individual, Color> indivColor = new HashMap<Individual, Color>();
	private Map<Species, JPanel> speciesPanel;
	private Color[] colors = new Color[] { new Color(255, 128, 128),
			new Color(255, 255, 128), new Color(128, 255, 128),
			new Color(0, 255, 128), new Color(128, 255, 255),
			new Color(0, 128, 255), new Color(255, 128, 192),
			new Color(255, 128, 255), new Color(255, 0, 0),
			new Color(255, 255, 0), new Color(128, 255, 0),
			new Color(0, 255, 64), new Color(0, 255, 255),
			new Color(0, 128, 192), new Color(128, 128, 192),
			new Color(255, 0, 255), new Color(128, 64, 64),
			new Color(255, 128, 64), new Color(0, 255, 0),
			new Color(0, 128, 128), new Color(0, 64, 128),
			new Color(128, 128, 255), new Color(128, 0, 64),
			new Color(255, 0, 128), new Color(128, 0, 0),
			new Color(255, 128, 0), new Color(0, 128, 0),
			new Color(0, 128, 64), new Color(0, 0, 255), new Color(0, 0, 160),
			new Color(128, 0, 128), new Color(128, 0, 255),
			new Color(64, 0, 0), new Color(128, 64, 0), new Color(0, 64, 0),
			new Color(0, 64, 64), new Color(0, 0, 128), new Color(0, 0, 64),
			new Color(64, 0, 64), new Color(64, 0, 128),
			new Color(128, 128, 0), new Color(128, 128, 64),
			new Color(128, 128, 128), new Color(64, 128, 128),
			new Color(192, 192, 192), new Color(255, 255, 255) };
	private int maxW;
	private int maxH;

	private JPanel toolTip = new JPanel();
	private JTextArea text = new JTextArea();
	JPanel showingPanel = null;

	public Map<Individual, Color> getIndivColor() {
		return indivColor;
	}

	public PlotSpeciesData(ArrayList<ArrayList<Species>> speciesData, int W,
			int H) {
		super();
		this.speciesData = speciesData;
		addMouseListener(this);
		addMouseMotionListener(this);
		this.setLayout(null);
		toolTip = new JPanel();
		this.add(toolTip);
		toolTip.add(text);
		toolTip.setLocation(100, 100);
		toolTip.setVisible(true);
		text.setText("abc");
		this.maxW = W;
		this.maxH = H - 10;

		int colorCount = 0;
		speciesRectangles = new HashMap<Species, Rectangle>();
		speciesPanel = new HashMap<Species, JPanel>();
		if (speciesData != null) {
			int currentX = 0;
			for (int i = 0; i < speciesData.size(); i++) {
				ArrayList<Species> thisGeneration = speciesData.get(i);
				int x = currentX;
				int y = 0;
				int w = maxW / speciesData.size();
				currentX += w;
				int totalNumber = 0;

				for (int j = 0; j < thisGeneration.size(); j++) {
					Species sp = thisGeneration.get(j);
					totalNumber += sp.individuals.size();
				}
				int currentY = 0;
				for (int j = 0; j < thisGeneration.size(); j++) {
					Species sp = thisGeneration.get(j);
					int x1 = x;
					int y1 = currentY;
					int w1 = w;
					int h1 = Math.round(maxH * sp.individuals.size()
							/ totalNumber);
					currentY += h1;
					// g2d.drawRect(x1, y1, w1, h1);
					if (indivColor.get(sp.representative) == null) {
						indivColor.put(sp.representative, colors[colorCount]);
						colorCount = (colorCount + 1) % colors.length;
					}

					speciesRectangles.put(sp, new Rectangle(x1, y1, w1, h1));

					JPanel panel = new JPanel();
					panel.setBounds(702, 68, 230, 236);
					panel.setLayout(new BorderLayout(0, 0));

					this.add(panel);
					JLabel label = new JLabel("<html><body>Generation:" + i
							+ "<br>" + "Species: "
							+ sp.representative.generationIndex + ","
							+ sp.representative.individualIndex + "<br>"
							+ "Fitness: "
							+ common.Static.df4.format(sp.getSpeciesFitness())
							+ "</body></html>");
					panel.add(label, BorderLayout.NORTH);
					panel.add(sp.getBestIndividual().getOligoModel()
							.getVisualization(120, 120), BorderLayout.CENTER);
					panel.setVisible(false);
					speciesPanel.put(sp, panel);
				}
			}
		}
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);

		Graphics2D g2d = (Graphics2D) g;
		int currentX = 0;
		for (int i = 0; i < speciesData.size(); i++) {
			ArrayList<Species> thisGeneration = speciesData.get(i);
			int w = maxW / speciesData.size();
			currentX += w;
			// g2d.drawString(String.valueOf(i), x, 15);
			for (int j = 0; j < thisGeneration.size(); j++) {
				Species sp = thisGeneration.get(j);
				Rectangle rec = speciesRectangles.get(sp);
				g2d.setColor(indivColor.get(sp.representative));
				g2d.fillRect(rec.x, rec.y, rec.width, rec.height);
				double speciesFitness = sp.getSpeciesFitness();
				DecimalFormat df = new DecimalFormat("#.##");
				g2d.setColor(Color.BLACK);
				// g2d.drawString(sp.representative.generationIndex + ","
				// + sp.representative.individualIndex, rec.x, rec.y +
				// rec.height
				// / 2);
			}

		}

	}

	@Override
	public void mouseClicked(MouseEvent arg0) {
		int x = arg0.getX();
		int y = arg0.getY();
		// System.out.println(arg0.getButton() + " " + x + " " + y);
		for (int i = 0; i < speciesData.size(); i++) {
			ArrayList<Species> thisGeneration = speciesData.get(i);
			for (int j = 0; j < thisGeneration.size(); j++) {
				Species sp = thisGeneration.get(j);
				Rectangle rec = speciesRectangles.get(sp);
				if (x > rec.x && y > rec.y && x < rec.x + rec.width
						&& y < rec.y + rec.height) {
					/*
					 * System.out.println(sp.representative.generationIndex +
					 * "," + sp.representative.individualIndex);
					 * System.out.println(common.Static.df4.format(sp
					 * .getSpeciesFitness()));
					 */if (arg0.getButton() == 1) {
						JFrame frame = new JFrame("Species "
								+ sp.representative.generationIndex + ","
								+ sp.representative.individualIndex
								+ " at generation " + i);
						frame.setSize(1300, 700);
						GraphDisplayer speciesGraph = new GraphDisplayer(1300,
								700);
						frame.add(speciesGraph.getContentPanel());
						frame.setVisible(true);
						Individual[] history = new Individual[i + 1];
						for (int k = 0; k <= i; k++) {
							for (Species sp1 : speciesData.get(k)) {
								if (sp.representative == sp.representative) {
									history[k] = sp.getBestIndividual();
								}
							}
						}
						speciesGraph.giveData(speciesData);
						speciesGraph.addSpecies(sp);
						speciesGraph.display();
						break;
					} else {
						JComponent component = (JComponent) arg0.getSource();
						component.setToolTipText("Mouse released on: "
								+ component.getClass().toString());
					}
				}
			}
		}
	}

	@Override
	public void mouseEntered(MouseEvent arg0) {

	}

	@Override
	public void mouseExited(MouseEvent arg0) {

	}

	@Override
	public void mousePressed(MouseEvent arg0) {

	}

	@Override
	public void mouseReleased(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseDragged(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseMoved(MouseEvent e) {
		int x = e.getX();
		int y = e.getY();
		boolean found = false;
		for (int i = 0; i < speciesData.size(); i++) {
			ArrayList<Species> thisGeneration = speciesData.get(i);
			for (int j = 0; j < thisGeneration.size(); j++) {
				Species sp = thisGeneration.get(j);
				Rectangle rec = speciesRectangles.get(sp);
				if (x > rec.x && y > rec.y && x < rec.x + rec.width
						&& y < rec.y + rec.height) {
					JPanel panel = speciesPanel.get(sp);
					int locX, locY;
					if (x < panel.getParent().getWidth() / 2) {
						locX = x + 5;
					} else {
						locX = x - panel.getWidth() - 5;
					}
					if (y < panel.getParent().getHeight() / 2) {
						locY = y + 5;
					} else {
						locY = y - panel.getHeight() - 5;
					}
					panel.setBounds(locX, locY, 120, 150);
					if (showingPanel != panel) {
						if (showingPanel != null) {
							showingPanel.setVisible(false);
						}
						panel.setVisible(true);
						showingPanel = panel;
					}
					found = true;
					return;
				}
			}
		}
		if (!found) {
			toolTip.setVisible(false);
		}

	}

}
